package priv.liaohaolong.fullstacktest.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.function.Function;

/**
 * JWT 工具类
 */
@Component
public class JwtUtils {

    private final SecretKey SECRET_KEY;

    private final long EXPIRATION;

    @Autowired
    public JwtUtils(JwtConfiguration jwtConfiguration) {
        this.SECRET_KEY = Keys.hmacShaKeyFor(jwtConfiguration.getSecret().getBytes()); // 配置密钥
        this.EXPIRATION = jwtConfiguration.getExpiration(); // 设置时间
    }

    // 生成 JWT
    public String generateToken(@NotNull UserDetails userDetails) {
        return Jwts.builder()
                .claims(new HashMap<>())
                .subject(userDetails.getUsername())
                .issuedAt(new Date(System.currentTimeMillis()))
                .expiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(SECRET_KEY)
                .compact();
    }

    // 从 JWT 中提取用户名
    public String extractUsername(String token) throws JwtException, IllegalArgumentException {
        return extractClaim(token, Claims::getSubject);
    }

    // 从 JWT 中提取过期时间
    public Date extractExpiration(String token) throws JwtException, IllegalArgumentException {
        return extractClaim(token, Claims::getExpiration);
    }

    // 验证 JWT 是否有效
    public @NotNull Boolean validateToken(String token, @NotNull UserDetails userDetails) throws JwtException, IllegalArgumentException {
        final String username = extractUsername(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    // 检查 JWT 是否过期
    private @NotNull Boolean isTokenExpired(String token) throws JwtException, IllegalArgumentException {
        return extractExpiration(token).before(new Date());
    }

    // 提取 JWT 中的声明
    private <T> T extractClaim(String token, @NotNull Function<Claims, T> claimsResolver) throws JwtException, IllegalArgumentException {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    // 解析 JWT
    private Claims extractAllClaims(String token) throws JwtException, IllegalArgumentException {
        return Jwts.parser()
                .verifyWith(SECRET_KEY)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

}
